#include "sessionextractor.h"

SessionExtractor::SessionExtractor()
{
    requests = 0;
    uniqueHosts = 0;
    sessions = 0;
    mostPopularPages = 0;

    sessionTime = 60*20; //20 minutes
    oneHostOneUser = true;
}

void SessionExtractor::setRequests(QList<Request *> *requests)
{
    this->requests = requests;
}

void SessionExtractor::setSessionTime(int sessionTime)
{
    this->sessionTime = sessionTime;
}

void SessionExtractor::findAllHosts()
{
    if(uniqueHosts != 0)
        delete uniqueHosts;
    uniqueHosts = new QList<QString>();

    for(int i = 0; i < requests->size(); ++i)
    {
        QString currentHost = requests->at(i)->host();
        if(uniqueHosts->indexOf(currentHost) == -1)
        {
            // New host
            uniqueHosts->append(currentHost);
        }
    }
}

void SessionExtractor::findAllSessions()
{
    if(sessions != 0)
        delete sessions;
    sessions = new QList<Session*>();

    int previous = 0;
    int userId = 0;
    Session *currentSession = 0;
    QString previousHost;
    for(int i = 0; i < uniqueHosts->size(); ++i)
    //for(int i = 0; i < 20; ++i)
    {
        previous = 0;
        //qDebug() << "\n\nSearching all sessions for host: " << uniqueHosts->at(i);
        for(int j = 0; j < requests->size(); ++j)
        {
            QString currentHost = uniqueHosts->at(i);
            if(requests->at(j)->host() == currentHost)
            {
                int currentTime = requests->at(j)->timestamp();
                if(currentTime - previous > sessionTime)
                {
                    //qDebug() << "new session has been found!";

                    // If oneHostOneUser is true, app has to decrese userId
                    if(currentHost == previousHost && oneHostOneUser == true)
                    {
                        userId--;
                    }

                    // If previous session has only one page, app has to remove it cuz it's a junk
                    if(userId > 0 && sessions->last()->getPages().size() == 1)
                    {
                        sessions->removeLast();
                        // Adjust userId counter
                        userId--;
                    }

                    // Create new session
                    currentSession = new Session;
                    currentSession->setHost(requests->at(j)->host());
                    currentSession->setUserName("user_" + QVariant(userId).toString());
                    currentSession->setSessionStartAt(requests->at(j)->timestamp());

                    // New session means new user
                    {
                        userId++;
                    }

                    // Append to the list
                    sessions->append(currentSession);
                }

                currentSession->addPage(requests->at(j)->page());
                currentSession->addTimestamp(requests->at(j)->timestamp());

                // For debug purpose only!
                //qDebug() << requests->at(j)->page() << requests->at(j)->timestamp();

                previous = currentTime;
                previousHost = currentHost;
            }
        }
    }
}

void SessionExtractor::findMostPopularPages()
{
    // First find all unique pages
    QList<QString> *uniquePages = new QList<QString>();
    for(int i = 0; i < requests->size(); ++i)
        if(uniquePages->indexOf(requests->at(i)->page()) == -1)
            uniquePages->append(requests->at(i)->page());

    // Insert zeros to mostPopular list
    mostPopularPages = new QList<QPair<QString,int> *>();
    for(int i = 0; i < uniquePages->size(); ++i)
        mostPopularPages->append(new QPair<QString, int>(uniquePages->at(i), 0));

    // And finally collect information about popularity
    for(int i = 0; i < requests->size(); ++i)
    {
        QString currentPage = requests->at(i)->page();
        // Find index of pair
        int index;
        for(int j = 0; j < mostPopularPages->size(); ++j)
        {
            if(mostPopularPages->at(j)->first == currentPage)
            {
                index = j;
                break;
            }
        }

        // Access to properly QPair
        QPair<QString, int> *currentPair = mostPopularPages->at(index);
        int c = currentPair->second;
        currentPair->second = c + 1;
    }

    // And finally let's sort results
    qSort(mostPopularPages->begin(), mostPopularPages->end(), sortLessThan);

    // Copy the most popular pages to QStringList
    //mostPopularPages = new QStringList();

    //for(int i = 0; i < mostPopular.size(); ++i)
    //{
    //    mostPopularPages->append(mostPopular.at(i)->first);
    //}

    // Release it
    delete uniquePages;
}

void SessionExtractor::compressSessions(int support)
{
    // This method requires information about frequency of occurrence each page
    if(mostPopularPages == 0)
        findMostPopularPages();

    // Create new list for new compressed sessions
    QList<Session *> *compressedSessions = new QList<Session *>();
    Session *currentSession = 0;
    QString currentPage = "";

    // Loop through all session
    for(int i = 0; i < sessions->size(); ++i)
    {
        currentSession = sessions->at(i);

        // Create new session based on old one
        Session *session = new Session(currentSession);

        // Loop through all pages in current session
        for(int j = 0; j < currentSession->getPages().size(); ++j)
        {
            currentPage = currentSession->getPages().at(j);

            // Now app has to check support of this page
            for(int k = 0; k  < mostPopularPages->size(); ++k)
            {
                if(mostPopularPages->at(k)->first == currentPage)
                {
                    if(mostPopularPages->at(k)->second >= support)
                    {
                        // Support is big enough, page can be saved
                        session->addPage(currentPage);
                    }
                    // Break the loop cuz app has already found page
                    break;
                }
            }
        }

        // Copy session if has at least 2 pages, in another case drop it
        if(session->getPages().size() > 1)
            compressedSessions->append(session);
        else
            delete session;
    }

    // Release memory of old list
    delete sessions;

    // And change pointer address
    sessions = compressedSessions;
}

void SessionExtractor::saveSessionsAsArff(QString filename)
{
    //
}

void SessionExtractor::saveUsersAsArff(QString filename)
{
    //
}

void SessionExtractor::debug()
{
    qDebug() << uniqueHosts->size();

    qDebug() << "Show all sessions";

    for(int i = 0; i < sessions->size(); ++i)
    {
        qDebug() << sessions->at(i)->getUserName() << sessions->at(i)->getHost() << sessions->at(i)->getPages();
    }

    //for(int i = 0; i < mostPopularPages->size(); ++i)
    //{
    //    qDebug() << mostPopularPages->at(i);
    //}
}

// For debug purpose only!~
QList<Session*> *SessionExtractor::getSessions()
{
    return this->sessions;
}

QList<QPair<QString, int> *> *SessionExtractor::getMostPopularPages()
{
    return this->mostPopularPages;
}


// Static method for sorting
bool SessionExtractor::sortLessThan(const QPair<QString, int> *p1, const QPair<QString, int> *p2)
{
    if(p1->second < p2->second)
        return false;
    else
        return true;
}
